#include <xpam/dsp/source.h>
#include <xpam/com/dshow.h>
#include <xpam/com/dshow/sample_grabber_cb.h>

namespace xpam
{
    namespace dsp
    {
        source::source()
            : _callback(0)
        { }

        source::~source()
        {
            delete (DexterLib::SampleGrabberCB*)_callback;
        }

        void source::avi_file(source & src, const std::string & filename)
        {
            XPAM_COM_USE_LIB;
            DexterLib::HRESULT_ex hr;

            DexterLib::IGraphBuilderPtr graph = DexterLib::IGraphBuilderPtr(CLSID_FilterGraph);
            DexterLib::ISampleGrabberPtr grabber(DexterLib::CLSID_SampleGrabber);
            DexterLib::ISampleGrabberCB * callback = new DexterLib::SampleGrabberCB();

            // setup decoding type
            DexterLib::_AMMediaType mt = {0};
            mt.majortype = MEDIATYPE_Video;
            mt.subtype = MEDIASUBTYPE_RGB24; //MEDIASUBTYPE_RGB8; //MEDIASUBTYPE_YV12

            hr = grabber->SetMediaType(&mt);
            hr = grabber->SetBufferSamples(TRUE);
            hr = grabber->SetCallback(callback, 0);
            hr = grabber->SetOneShot(FALSE);

            // add filters
            DexterLib::IBaseFilterPtr sourceFilter;
            hr = graph->AddSourceFilter(_bstr_t(_videoLocation.c_str()), L"Video Source", &sourceFilter);

            DexterLib::IBaseFilterPtr grabberFilter(grabber);
            hr = graph->AddFilter(grabberFilter, L"Video Grabber");

            // connect filters
            hr = graph->Connect(DexterLib::dsow::output_pin(sourceFilter), GetInPin(grabberFilter));

            if (_showWindow)
            {
                hr = graph->Render(GetOutPin(grabberFilter));
            }
            else
            {
                DexterLib::IBaseFilterPtr nullRender(DexterLib::CLSID_NullRenderer);
                hr = graph->AddFilter(nullRender, L"Video render");
                hr = graph->Connect(GetOutPin(grabberFilter), GetInPin(nullRender));
            }

            // get video parameters
            hr = sampleGrabber->GetConnectedMediaType(&mt);  
            if (mt.pbFormat)
            {
                VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *) mt.pbFormat;  
                _size.x  = vih->bmiHeader.biWidth;  
                _size.y = vih->bmiHeader.biHeight;  

                if (_notifyFrameSize)
                {
                    _notifyFrameSize(_size);
                }
            }
            DexterLib::FreeMediaTypeHelper(mt);  

            // turn off sync clock for max speed
            if (false == _enableRealTime)
            {
                DexterLib::IMediaFilterPtr mediaFilter(graph);
                mediaFilter->SetSyncSource(NULL);
            }
        }

        void source::go(frame & fr)
        {
            if (_callback)
                ((DexterLib::dshow::sample_grabber_cb*)_callback)->frame(fr);
        }
    }
}